package com.vert.utils;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @Classname ClassScanUtils
 * @Description TODO
 * @Date 2022/5/24 18:22
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class ClazzScanUtils {

      private static ConcurrentHashMap<String,Object> cache = new ConcurrentHashMap<>();

      private static List<String> classPaths=new ArrayList<>();

      private static List<Class<?>> classList=new ArrayList<>();

      public static void scanClass(Class<?> clazz) throws ClassNotFoundException {
        //包名
        String basePack = clazz.getPackage().getName();
        if(clazz.getResource("/")==null){
            return;
        }
        //先把包名转换为路径,首先得到项目的classpath
        String classpath = clazz.getResource("/").getPath();
        //然后把我们的包名basPach转换为路径名
        basePack = basePack.replace(".", File.separator);
        //然后把classpath和basePack合并
        String searchPath = classpath + basePack;
        doPath(new File(searchPath));
        //这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象
        for (String s : classPaths) {
            s = s.replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");
            Class cls = Class.forName(s);
            classList.add(cls);
        }
      }
      /**
       * 该方法会得到所有的类，将类的绝对路径写入到classPaths中
       * @param file
       */
      private static void doPath(File file) {
        if (file.isDirectory()) {//文件夹
          //文件夹我们就递归
          File[] files = file.listFiles();
          for (File f1 : files) {
            doPath(f1);
          }
        } else {//标准文件
          //标准文件我们就判断是否是class文件
          if (file.getName().endsWith(".class")) {
            //如果是class文件我们就放入我们的集合中。
            classPaths.add(file.getPath());
          }
        }
      }

      public static List<Class<?>> getClassPaths(){
        return classList;
      }

  public static void searchClass(Class< ? > clazz) throws IOException, ClassNotFoundException {
    String basePack = clazz.getPackage().getName();
    //通过当前线程得到类加载器从而得到URL的枚举
    Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(basePack.replace(".", "/"));
    try {
      while (urlEnumeration.hasMoreElements()) {
        URL url = urlEnumeration.nextElement();//得到的结果大概是：jar:file:/C:/Users/ibm/.m2/repository/junit/junit/4.12/junit-4.12.jar!/org/junit
        String protocol = url.getProtocol();//大概是jar
        if ("jar".equalsIgnoreCase(protocol)) {
          //转换为JarURLConnection
          JarURLConnection connection = (JarURLConnection) url.openConnection();
          if (connection != null) {
            JarFile jarFile = connection.getJarFile();
            if (jarFile != null) {
              //得到该jar文件下面的类实体
              Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
              while (jarEntryEnumeration.hasMoreElements()) {
                            /*entry的结果大概是这样：
                                    org/
                                    org/junit/
                                    org/junit/rules/
                                    org/junit/runners/*/
                JarEntry entry = jarEntryEnumeration.nextElement();
                String jarEntryName = entry.getName();
                //这里我们需要过滤不是class文件和不在basePack包名下的类
                if (jarEntryName.contains(".class") && jarEntryName.replaceAll("/",".").startsWith(basePack)) {
                  String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replace("/", ".");
                  System.out.println(className);
                  classPaths.add(className);
                  Class< ? > clsClass=Class.forName(className);
                  classList.add(clsClass);
                }
              }
            }
          }
        }
      }
    }catch (Exception e){
      e.printStackTrace();
    }

  }
}
